home *** CD-ROM | disk | FTP | other *** search
- /*
- File: ScriptID.cpp
-
- Contains: Implementation of ScriptingIDManager.
-
- Owned by: Craig Carper
-
- Copyright: © 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <1> 11/19/96 CC first checked in
- To Do:
- */
-
- #ifndef _ScriptID_
- #include "ScriptID.h"
- #endif
-
- #ifndef SOM_CMStorageUnit_xh
- #include <CMSU.xh>
- #endif
-
- #ifndef _CMAPI_
- #include "CMAPI.h"
- #endif
-
- #ifndef _SESSHDR_
- #include "SessHdr.h"
- #endif
-
- #ifndef _LINKLIST_
- #include "LinkList.h"
- #endif
-
- #ifndef SOM_ODFrame_xh
- #include <Frame.xh>
- #endif
-
- #ifndef _ODMEMORY_
- #include <ODMemory.h>
- #endif
-
- #ifndef _TEMPOBJ_
- #include <TempObj.h>
- #endif
-
- #ifndef SOM_Module_OpenDoc_StdProps_defined
- #include <StdProps.xh>
- #endif
-
- #ifndef SOM_Module_OpenDoc_StdTypes_defined
- #include <StdTypes.xh>
- #endif
-
- #ifndef _ODDEBUG_
- #include "ODDebug.h"
- #endif
-
- #ifndef _STORUTIL_
- #include <StorUtil.h>
- #endif
-
- #ifndef _ISOSTR_
- #include "ISOStr.h"
- #endif
-
- #ifndef _FLIPEND_
- #include "FlipEnd.h"
- #endif
-
- #ifndef _STDTYPIO_
- #include "StdTypIO.h"
- #endif
-
- //==============================================================================
- // Debugging
- //==============================================================================
-
- #if ODDebug
- #define ODDebug_ScriptingIDs 1
- #endif
-
- //==============================================================================
- // Constants
- //==============================================================================
-
- const int kODULongLen = 4;
-
- const int kODInitialNumEntries = 10;
-
- const long kFirstCMObjectID = 65535; // Used for sanity checks
-
- //==============================================================================
- // Local Functions
- //==============================================================================
-
- static void WriteULongToFocusedSU(ODStorageUnit* su,
- Environment* ev,
- ODULong value);
-
- static ODULong GetULongFromFocusedSU(ODStorageUnit* su, Environment* ev);
-
- //------------------------------------------------------------------------------
- // WriteULongToFocusedSU
- //------------------------------------------------------------------------------
-
- static void WriteULongToFocusedSU(ODStorageUnit* su,
- Environment* ev,
- ODULong value)
- {
- value = ConvertODULongToStd(value);
- StorageUnitSetValue(su, ev, kODULongLen, (ODValue) &value);
- }
-
- //------------------------------------------------------------------------------
- // GetULongFromFocusedSU
- //------------------------------------------------------------------------------
-
- static ODULong GetULongFromFocusedSU(ODStorageUnit* su, Environment* ev)
- {
- ODULong value;
- StorageUnitGetValue(su, ev, kODULongLen, (ODValue)&value);
- return ConvertODULongFromStd(value);
- }
-
- //------------------------------------------------------------------------------
- // FrameIsInLimbo
- //------------------------------------------------------------------------------
- //
- // It suffices to check containing frames to see if a frame is in-limbo.
- // If the source frame of a window becomes "in-limbo", the window must
- // be closed, and thus its not possible to access the source frame. [cc]
-
- static ODBoolean FrameIsInLimbo(Environment* ev, ODFrame* frame)
- {
- ODBoolean isInLimbo = frame->IsInLimbo(ev);
-
- TempODFrame containingFrame = frame->AcquireContainingFrame(ev);
-
- while ( !isInLimbo && (containingFrame != kODNULL) )
- {
- isInLimbo = containingFrame->IsInLimbo(ev);
- ODFrame* nextFrame = containingFrame->AcquireContainingFrame(ev);
- ODReleaseObject(ev, containingFrame);
- containingFrame = nextFrame;
- }
-
- return isInLimbo;
- }
-
- //======================================================================================
- // Class CMIDLink
- //======================================================================================
-
- class CMIDLink : public Link
- {
- public:
- CMIDLink(CMObjectID cmid);
- virtual ~CMIDLink();
-
- CMObjectID GetCMID() { return fCMID; }
-
- private:
- CMObjectID fCMID;
- };
-
- //------------------------------------------------------------------------------
- // CMIDLink Constructor
- //------------------------------------------------------------------------------
-
- CMIDLink::CMIDLink(CMObjectID cmid)
- {
- fCMID = cmid;
- }
-
- //------------------------------------------------------------------------------
- // CMIDLink Destructor
- //------------------------------------------------------------------------------
-
- CMIDLink::~CMIDLink()
- {
- }
-
- //=====================================================================================
- // Class CMIDList
- //=====================================================================================
-
- class CMIDList
- {
- friend class CMIDListIterator;
-
- public:
- CMIDList(ODMemoryHeapID heapID) { fHeapID = heapID; }
- ~CMIDList();
-
- void Add(CMObjectID cmid);
- void Remove(CMObjectID cmid);
- ODUShort Count();
- CMObjectID First();
-
- private:
- LinkedList fImplementation;
- ODMemoryHeapID fHeapID;
- };
-
- //------------------------------------------------------------------------------
- // CMIDList Destructor
- //------------------------------------------------------------------------------
-
- CMIDList::~CMIDList()
- {
- fImplementation.DeleteAllLinks();
- }
-
- //------------------------------------------------------------------------------
- // CMIDList::Add
- //------------------------------------------------------------------------------
-
- void CMIDList::Add(CMObjectID cmid)
- {
- CMIDLink* link = new(fHeapID) CMIDLink(cmid); // "new" THROWS for non-SOM objects
-
- fImplementation.AddFirst((Link*) link);
- }
-
- //------------------------------------------------------------------------------
- // CMIDList::Remove
- //------------------------------------------------------------------------------
-
- void CMIDList::Remove(CMObjectID cmid)
- {
- LinkedListIterator iter(&fImplementation);
-
- for (Link* aLink = iter.First();
- iter.IsNotComplete();
- aLink = iter.Next())
- {
- CMIDLink* cmidLink = (CMIDLink*) aLink;
- if ( cmidLink->GetCMID() == cmid )
- {
- fImplementation.Remove(*aLink);
- delete cmidLink;
- break;
- }
- }
- }
-
- //------------------------------------------------------------------------------
- // CMIDList::Count
- //------------------------------------------------------------------------------
-
- ODUShort CMIDList::Count()
- {
- return fImplementation.Count();
- }
-
- //------------------------------------------------------------------------------
- // CMIDList::First
- //------------------------------------------------------------------------------
-
- CMObjectID CMIDList::First()
- {
- CMIDLink* cmidLink = (CMIDLink*) fImplementation.First();
- return cmidLink->GetCMID();
- }
-
- //=====================================================================================
- // Class CMIDListIterator
- //=====================================================================================
-
- class CMIDListIterator
- {
- public:
- CMIDListIterator(CMIDList* cmidList) : fIterator(&(cmidList->fImplementation)) { }
- ~CMIDListIterator();
-
- CMObjectID First();
- CMObjectID Next();
- ODBoolean IsNotComplete();
- void RemoveCurrent();
-
- private:
- LinkedListIterator fIterator;
- };
-
- //------------------------------------------------------------------------------
- // CMIDListIterator Destructor
- //------------------------------------------------------------------------------
-
- CMIDListIterator::~CMIDListIterator()
- {
- }
-
- //------------------------------------------------------------------------------
- // CMIDListIterator::First
- //------------------------------------------------------------------------------
-
- CMObjectID CMIDListIterator::First()
- {
- CMIDLink* cmidLink = (CMIDLink*) fIterator.First();
- if ( cmidLink )
- return cmidLink->GetCMID();
- else
- return kODNULLID; // There is no "null" container mgr object id,
- // so this may be a valid id! Clients must call
- // IsNotComplete before using result.
- }
-
- //------------------------------------------------------------------------------
- // CMIDListIterator::Next
- //------------------------------------------------------------------------------
-
- CMObjectID CMIDListIterator::Next()
- {
- CMIDLink* cmidLink = (CMIDLink*) fIterator.Next();
- if ( cmidLink )
- return cmidLink->GetCMID();
- else
- return kODNULLID; // There is no "null" container mgr object id,
- // so this may be a valid id! Clients must call
- // IsNotComplete before using result.
- }
-
- //------------------------------------------------------------------------------
- // CMIDListIterator::IsNotComplete
- //------------------------------------------------------------------------------
-
- ODBoolean CMIDListIterator::IsNotComplete()
- {
- return fIterator.IsNotComplete();
- }
-
- //------------------------------------------------------------------------------
- // CMIDListIterator::RemoveCurrent
- //------------------------------------------------------------------------------
-
- void CMIDListIterator::RemoveCurrent()
- {
- fIterator.RemoveCurrent();
- }
-
- //==============================================================================
- // Class CMObjectIDOrList
- //==============================================================================
-
- class CMObjectIDOrList
- {
- public:
- CMObjectIDOrList() : fIsEmpty(kODTrue) { }
- CMObjectIDOrList(CMObjectID cmid) : fIsEmpty(kODFalse),
- fIsList(kODFalse),
- fCMID(cmid) { }
-
- void Add(CMObjectID cmid, ODMemoryHeapID heapID);
- void Remove(CMObjectID cmid);
- ODUShort Count();
- CMObjectID First();
- CMIDList* GetCMIDList();
- ODBoolean IsEmpty() { return fIsEmpty; }
- ODBoolean IsList() { return fIsList; }
-
- ODBoolean fIsEmpty;
- ODBoolean fIsList;
- union {
- CMObjectID fCMID;
- CMIDList* fCMIDList;
- };
- };
-
- //------------------------------------------------------------------------------
- // CMObjectIDOrList::Add
- //------------------------------------------------------------------------------
-
- void CMObjectIDOrList::Add(CMObjectID cmid, ODMemoryHeapID heapID)
- {
- WASSERT(!fIsEmpty);
-
- if ( fIsEmpty )
- {
- fCMID = cmid;
- fIsEmpty = kODFalse;
- fIsList = kODFalse;
- }
- else if ( fIsList )
- {
- WASSERT(fCMIDList != kODNULL);
- if ( fCMIDList )
- {
- fCMIDList->Add(cmid);
- }
- else
- THROW(kODErrNullCMIDList);
- }
- else
- {
- CMIDList* cmidList = new(heapID) CMIDList(heapID); // "new" THROWS for non-SOM objects
- TRY
- cmidList->Add(fCMID);
- cmidList->Add(cmid);
- CATCH_ALL
- delete cmidList;
- RERAISE;
- ENDTRY
- fCMIDList = cmidList;
- fIsList = kODTrue;
- }
- }
-
- //------------------------------------------------------------------------------
- // CMObjectIDOrList::Remove
- //------------------------------------------------------------------------------
-
- void CMObjectIDOrList::Remove(CMObjectID cmid)
- {
- WASSERT(!fIsEmpty);
- if ( fIsEmpty )
- THROW(kODErrEmptyCMObjectIDOrList);
- else if ( fIsList )
- {
- WASSERT(fCMIDList != kODNULL);
- if ( fCMIDList )
- {
- WASSERT(fCMIDList->Count() > 1);
- fCMIDList->Remove(cmid);
- if ( fCMIDList->Count() == 1 )
- {
- CMObjectID onlyCMID = fCMIDList->First();
- delete fCMIDList;
- fCMID = onlyCMID;
- fIsList = kODFalse;
- }
- }
- else
- THROW(kODErrNullCMIDList);
- }
- else
- {
- WASSERT(cmid == fCMID);
- if ( cmid != fCMID )
- THROW(kODErrCMObjectIDNotFound);
- fIsEmpty = kODTrue;
- }
- }
-
- //------------------------------------------------------------------------------
- // CMObjectIDOrList::Count
- //------------------------------------------------------------------------------
-
- ODUShort CMObjectIDOrList::Count()
- {
- if ( fIsEmpty )
- return 0;
- else if ( !fIsList )
- return 1;
- else
- return fCMIDList->Count();
- }
-
- //------------------------------------------------------------------------------
- // CMObjectIDOrList::First
- //------------------------------------------------------------------------------
-
- CMObjectID CMObjectIDOrList::First()
- {
- WASSERT(!fIsEmpty);
- if ( fIsEmpty )
- {
- THROW(kODErrEmptyCMObjectIDOrList);
- return kODNULLID; // not a reliable null value!
- }
- else if ( fIsList )
- return fCMIDList->First();
- else
- return fCMID;
- }
-
- //------------------------------------------------------------------------------
- // CMObjectIDOrList::GetCMIDList
- //------------------------------------------------------------------------------
-
- CMIDList* CMObjectIDOrList::GetCMIDList()
- {
- WASSERT(!fIsEmpty);
- if ( fIsEmpty )
- THROW(kODErrEmptyCMObjectIDOrList);
- if ( !fIsList )
- THROW(kODErrNoCMIDList);
- return fCMIDList;
- }
-
- //==============================================================================
- // ScriptingIDManager
- //==============================================================================
-
- // Theory of Operation
- //
- // This class maintains a mapping from scripting IDs to their underlying
- // container manager objects.
- //
- // CMObjectIDs - Identify container manager objects (i.e. bento objects).
- // Persistent across closing and reopening a draft. Private to the
- // container suite (although earlier versions of OpenDoc used these values
- // for persistent IDs).
- //
- // Object IDs - Identify OpenDoc objects. Based on CMObjectIDs. Transient,
- // cannot be used after a draft has been closed.
- //
- // Peristent IDs - Also based on CMObjectIDs, but unlike Object IDs these are
- // preserved across closing and reopening a draft. Used only for scripting.
- //
- // Note that there is no CMObjectID value guaranteed to be distinct from any
- // valid value. Since previous versions of OpenDoc exposed CMObjectIDs as
- // persistent ids, there is no "null" scripting id. If an unknown scripting id
- // is used to retrieve a persistent object, the scripting id will be interpreted
- // as a CMObjectID.
- //
- // Entries in the table are only eliminated when objects are explicitly removed.
- // This is probably ok for frames, which have a remove protocol, but could cause
- // obsolete entries for parts to remain.
- //
- // In the current implementation, GetScriptingID is a little expensive, as
- // the table is searched for a matching entry. This can be sped up if it proves
- // to be a performance problem.
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::~ScriptingIDManager
- //------------------------------------------------------------------------------
- ScriptingIDManager::~ScriptingIDManager()
- {
- Environment* ev = somGetGlobalEnvironment();
-
- if ( fScriptingTable != kODNULL )
- {
- ODPersistentObjectID sid;
- CMObjectIDOrList cmidOrList;
- OpenHashTableIterator iter(fScriptingTable);
-
- for (iter.First(&sid, &cmidOrList);
- iter.IsNotComplete();
- iter.Next(&sid, &cmidOrList))
- {
- if ( cmidOrList.IsList() )
- {
- // Unexpected; undo actions should have committed so
- // only one object per scripting id should remain.
- WARN("Multiple objects have scripting id %d", sid);
- CMIDList* cmidList = cmidOrList.GetCMIDList();
- delete cmidList;
- iter.RemoveCurrent();
- }
- }
-
- delete fScriptingTable;
- fScriptingTable = kODNULL;
- }
- }
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::InitScriptingIDManager
- //------------------------------------------------------------------------------
- void ScriptingIDManager::InitScriptingIDManager(Environment* ev,
- ODMemoryHeapID heapID,
- CMDraft* draft)
- {
- fDirty = kODFalse;
- fHeapID = heapID;
- fDraft = draft;
- fLastScriptingID = 0;
-
- ODULong size = 0;
- ODULong count = 0;
-
- TRY
- TempODStorageUnit su = kODNULL;
- TempODStorageUnit draftPropertiesSU = fDraft->AcquireDraftProperties(ev);
- ODStorageUnitID id = ODGetWeakSURefProp(ev, draftPropertiesSU,
- kODPropScriptingIDs, kODWeakStorageUnitRef);
-
- if ( id != kODNULLID )
- {
- su = fDraft->AcquireStorageUnit(ev, id);
-
- if ( ODSUExistsThenFocus(ev, su, kODPropScriptingIDs, kODULongSequence) )
- {
- size = su->GetSize(ev);
- if ( size > kODULongLen )
- count = (size - kODULongLen) / (kODULongLen+kODULongLen);
- }
- }
-
- fScriptingTable =
- new(heapID) OpenHashTable(OpenHashTable::StdEqual,
- OpenHashTable::StdHash,
- heapID); // "new" THROWS for non-SOM objects
- fScriptingTable->Initialize(kODInitialNumEntries+count,
- sizeof(ODPersistentObjectID),
- sizeof(CMObjectIDOrList));
-
- if ( size > 0 )
- {
- su->SetOffset(ev, 0);
-
- // First long is the greatest scripting id assigned.
- fLastScriptingID = GetULongFromFocusedSU(su, ev);
-
- if ( count > 0 )
- {
- ODPersistentObjectID scriptingID;
- CMObjectIDOrList cmidOrList;
- CMObjectID cmid;
-
- do
- {
- scriptingID = GetULongFromFocusedSU(su, ev);
- cmid = GetULongFromFocusedSU(su, ev);
-
- WASSERT(scriptingID < kFirstCMObjectID);
-
- if ( scriptingID > fLastScriptingID )
- {
- WARN("Object's scripting id %d is beyond expected limit of %d", scriptingID, fLastScriptingID);
- fLastScriptingID = scriptingID;
- }
-
- if ( fScriptingTable->GetValue(&scriptingID, &cmidOrList) )
- {
- WARN("Multiple objects have scripting id %d", scriptingID);
- cmidOrList.Add(cmid, fHeapID);
- }
- else
- {
- cmidOrList.fCMID = cmid;
- cmidOrList.fIsList = kODFalse;
- cmidOrList.fIsEmpty = kODFalse;
- }
-
- fScriptingTable->ReplaceEntry(&scriptingID, &cmidOrList);
- }
- while ( --count > 0 );
- }
- }
- CATCH_ALL
- delete fScriptingTable;
- fScriptingTable = kODNULL;
- RERAISE;
- ENDTRY
- }
-
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::SearchForScriptingID
- //------------------------------------------------------------------------------
- ODBoolean ScriptingIDManager::SearchForScriptingID(
- Environment *ev,
- CMObjectID objectID,
- ODPersistentObjectID& scriptingID)
- {
- // Search for the persistent ID associated with the argument cm object.
- // This is an expensive way to get a persistent ID, but might not be
- // bad overall if persistent IDs are only requested for a small percentage
- // of frames and parts. If performance is a problem, and multiple requests
- // are made for the same objects, we could cache each cmid-scriptingID pair
- // as they are looked up.
- // Two alternatives to this lookup: (1) When the draft is opened, create a
- // second table that maps from cmid to persistent id. This table would
- // contain an entry for each part and frame created in the document.
- // (2) Store the persistent ID in the storage unit. The problem here is
- // that CMStorageUnit::CloneInto will clone the persistent id property,
- // which is not desired. That could be prevented by modifying CMStorageUnit,
- // but that couples another class into this issue.
-
- ODBoolean found = kODFalse;
- ODPersistentObjectID sid;
-
- CMObjectIDOrList cmidOrList;
- OpenHashTableIterator iter(fScriptingTable);
-
- for (iter.First(&sid, &cmidOrList);
- !found && iter.IsNotComplete();
- iter.Next(&sid, &cmidOrList))
- {
- if ( cmidOrList.IsList() )
- {
- CMIDListIterator iter(cmidOrList.GetCMIDList());
- for (CMObjectID cmid = iter.First();
- !found && iter.IsNotComplete();
- cmid = iter.Next())
- {
- if ( cmid == objectID )
- {
- found = kODTrue;
- scriptingID = sid;
- }
- }
- }
- else
- {
- if ( cmidOrList.fCMID == objectID )
- {
- found = kODTrue;
- scriptingID = sid;
- }
- }
- }
-
- return found;
- }
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::GetScriptingID
- //------------------------------------------------------------------------------
- ODPersistentObjectID ScriptingIDManager::GetScriptingID(
- Environment *ev,
- CMObjectID objectID)
- {
- ODPersistentObjectID scriptingID;
-
- if ( !this->SearchForScriptingID(ev, objectID, scriptingID) )
- scriptingID = this->AssignScriptingID(ev, objectID);
-
- return scriptingID;
- }
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::AcquirePersistentObject
- //------------------------------------------------------------------------------
-
- ODPersistentObject* ScriptingIDManager::AcquirePersistentObject(
- Environment *ev,
- ODPersistentObjectID scriptingID,
- ODObjectType* objectType)
- {
- CMObjectIDOrList cmidOrList;
- ODPersistentObject* object = kODNULL;
-
- if ( fScriptingTable->GetValue(&scriptingID, &cmidOrList) )
- {
- if ( cmidOrList.IsList() )
- {
- CMIDList* cmidList = cmidOrList.GetCMIDList();
-
- // Begin a new scope for iter
- {
- ODBoolean skip = kODFalse;
-
- CMIDListIterator iter(cmidList);
- for (CMObjectID cmid = iter.First();
- iter.IsNotComplete();
- cmid = iter.Next())
- {
- TempODFrame frame = kODNULL;
-
- // If the table contains an invalid entry, remove the cmid from
- // the linked list and continue the iteration. Note that this
- // may cause the list to contain fewer than 2 entries.
- TRY
- frame = (ODFrame*) fDraft->AcquirePersistentObjectByCMObjectID(ev, cmid, objectType);
- CATCH_ALL
- if ( ErrorCode() == kODErrInvalidPersistentObjectID )
- {
- WARN("Invalid object %d associated with scripting ID %d", cmid, scriptingID);
- iter.RemoveCurrent();
- skip = kODTrue;
- }
- else
- RERAISE;
- ENDTRY
-
- if ( skip )
- {
- skip = kODFalse;
- continue;
- }
-
- if ( ODISOStrEqual(*objectType, kODFrameObject) )
- {
- if ( !FrameIsInLimbo(ev, frame) )
- {
- #ifdef ODDebug_ScriptingIDs
- if ( object != kODNULL )
- {
- WARN("Multiple frames with the same scripting ID are not in-limbo!");
- }
- else
- {
- object = frame;
- frame.DontRelease();
- }
- #else
- object = frame;
- frame.DontRelease();
- break;
- #endif
- }
- }
- else
- {
- THROW(kODErrInvalidObjectType);
- }
- }
- }
-
- // If the list contained invalid entries, it may be too short
- if ( cmidList->Count() == 0 )
- {
- fScriptingTable->RemoveEntry(&scriptingID);
- fDirty = kODTrue;
- delete cmidList;
- }
- else if ( cmidList->Count() == 1 )
- {
- cmidOrList.fCMID = cmidList->First();
- cmidOrList.fIsList = kODFalse;
- fScriptingTable->ReplaceEntry(&scriptingID, &cmidOrList);
- fDirty = kODTrue;
- delete cmidList;
- }
-
- if ( object == kODNULL )
- {
- // All table entries with the scriptingID are in-limbo.
- // This is valid if a frame is moved out of the document.
- THROW(kODErrInvalidPersistentObjectID);
- }
- }
- else
- {
- // If the table contains an invalid entry, remove it!
- TRY
- object = fDraft->AcquirePersistentObjectByCMObjectID(ev, cmidOrList.First(), objectType);
- CATCH_ALL
- if ( ErrorCode() == kODErrInvalidPersistentObjectID )
- {
- WARN("Invalid object %d is no longer associated with scripting ID %d", cmidOrList.First(), scriptingID);
- // Just remove the entry from the table, since
- // cmidOrList contains a single cmid.
- fScriptingTable->RemoveEntry(&scriptingID);
- }
- RERAISE;
- ENDTRY
- }
- }
- else
- {
- object = fDraft->AcquirePersistentObjectByCMObjectID(ev, scriptingID, objectType);
- }
-
- return object;
- }
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::AssignScriptingID
- //------------------------------------------------------------------------------
-
- ODPersistentObjectID ScriptingIDManager::AssignScriptingID(
- Environment* ev,
- CMObjectID cmid)
- {
- CMObjectIDOrList cmidOrList(cmid);
-
- ++fLastScriptingID;
-
- fScriptingTable->ReplaceEntry(&fLastScriptingID, &cmidOrList);
-
- fDirty = kODTrue;
-
- return fLastScriptingID;
- }
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::TransferScriptingID
- //------------------------------------------------------------------------------
-
- ODPersistentObjectID ScriptingIDManager::TransferScriptingID(
- Environment* ev,
- CMObjectID fromCMID,
- CMObjectID toCMID)
- {
- // We loose backward compatability here with scripts that use
- // old persistent IDs, since we transfer new scripting IDs.
- ODPersistentObjectID scriptingID = GetScriptingID(ev, fromCMID);
-
- #ifdef ODDebug_ScriptingIDs
- PRINT("Transferring scripting id %d from object %d to %d\n", scriptingID, fromCMID, toCMID);
- #endif
-
- CMObjectIDOrList cmidOrList;
- if ( fScriptingTable->GetValue(&scriptingID, &cmidOrList) )
- {
- cmidOrList.Add(toCMID, fHeapID);
- fScriptingTable->ReplaceEntry(&scriptingID, &cmidOrList);
- fDirty = kODTrue;
- }
- else
- {
- // Unexpected condition. Rather than fail, just assign a new scripting ID
- WARN("Transfer of scripting id %d to object %d failed", scriptingID, toCMID);
- scriptingID = GetScriptingID(ev, toCMID);
- }
- return scriptingID;
- }
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::DropScriptingID
- //------------------------------------------------------------------------------
-
- void ScriptingIDManager::DropScriptingID(Environment* ev,
- CMObjectID cmid)
- {
- #ifdef ODDebug_ScriptingIDs
- PRINT("Droppinging scripting id for object %d\n", cmid);
- #endif
-
- ODPersistentObjectID scriptingID;
- if ( this->SearchForScriptingID(ev, cmid, scriptingID) )
- {
- CMObjectIDOrList cmidOrList;
- if ( fScriptingTable->GetValue(&scriptingID, &cmidOrList) )
- {
- cmidOrList.Remove(cmid);
- if ( cmidOrList.IsEmpty() )
- fScriptingTable->RemoveEntry(&scriptingID);
- else
- fScriptingTable->ReplaceEntry(&scriptingID, &cmidOrList);
- }
-
- fDirty = kODTrue;
- }
- }
-
- //------------------------------------------------------------------------------
- // ScriptingIDManager::Save
- //------------------------------------------------------------------------------
-
- void ScriptingIDManager::Save(Environment* ev)
- {
- if ( fDirty )
- {
- TempODStorageUnit su = kODNULL;
- TempODStorageUnit draftPropertiesSU = fDraft->AcquireDraftProperties(ev);
-
- ODStorageUnitID id = ODGetWeakSURefProp(ev, draftPropertiesSU,
- kODPropScriptingIDs, kODWeakStorageUnitRef);
-
- if ( id == kODNULLID )
- {
- su = fDraft->CreateStorageUnit(ev);
- id = su->GetID(ev);
- ODSetWeakSURefProp(ev, draftPropertiesSU, kODPropScriptingIDs,
- kODWeakStorageUnitRef, id);
- }
- else
- {
- su = fDraft->AcquireStorageUnit(ev, id);
- }
-
- ODSUForceFocus(ev, su, kODPropScriptingIDs, kODULongSequence);
- su->SetOffset(ev, 0);
- ODULong oldSize = su->GetSize(ev);
-
- // First long is the greatest scripting id assigned.
- WriteULongToFocusedSU(su, ev, fLastScriptingID);
-
- ODPersistentObjectID scriptingID;
- CMObjectIDOrList cmidOrList;
- OpenHashTableIterator iter(fScriptingTable);
-
- for (iter.First(&scriptingID, &cmidOrList);
- iter.IsNotComplete();
- iter.Next(&scriptingID, &cmidOrList))
- {
- if ( cmidOrList.IsList() )
- {
- // When this method is called, the undo stack must be committed,
- // so in theory there should be no lin-limbo frames and hense
- // no lists in the table.
- // Just to be safe, dump out the list anyway.
- WARN("There are %d objects assigned the same scripting ID %d", cmidOrList.Count(), scriptingID);
- CMIDListIterator iter(cmidOrList.GetCMIDList());
- for (CMObjectID cmid = iter.First();
- iter.IsNotComplete();
- cmid = iter.Next())
- {
- WriteULongToFocusedSU(su, ev, scriptingID);
- WriteULongToFocusedSU(su, ev, cmid);
- #ifdef ODDebug_ScriptingIDs
- PRINT("%d ", cmid);
- #endif
- }
- #ifdef ODDebug_ScriptingIDs
- PRINT("\n");
- #endif
- }
- else
- {
- WriteULongToFocusedSU(su, ev, scriptingID);
- WriteULongToFocusedSU(su, ev, cmidOrList.fCMID);
- }
- }
-
- ODULong newSize = su->GetOffset(ev);
- if ( oldSize > newSize )
- su->DeleteValue(ev, oldSize - newSize);
-
- fDirty = kODFalse;
- }
- }
-